/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.security.shiro.config;

import org.apache.shiro.config.Ini;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.springframework.beans.factory.FactoryBean;
import org.vacoor.nothing.security.entity.Permission;
import org.vacoor.nothing.security.service.PermissionService;

import java.util.List;

import static org.apache.shiro.config.Ini.Section;

/**
 * 该类无法解决动态 filter 问题, 动态修改的 filter 需要重启应用
 * {@link org.vacoor.nothing.security.shiro.filter.mgt.CustomFilterChainManager}
 * <p/>
 * 参考网上资料 及 {@link org.apache.shiro.spring.web.ShiroFilterFactoryBean}
 * 利用Spring FactoryBean 实现从数据库加载 Shiro FilterChain 定义,
 * 主要用于处理资源的权限控制, 使用{@link #setDbFirst(boolean)} 来解决 Shiro 的最先匹配原则
 *
 * @author vacoor
 * @see org.vacoor.nothing.security.shiro.filter.mgt.CustomFilterChainManager
 * @deprecated
 */
public class FilterChainDefinitionSectionFactoryBean implements FactoryBean<Section> {
    public static final String DB_SECTION_NAME = "db_section";
    public static final String IGNORE_URL = "#";

    private String filterChainDefinitions;  // 接收通过xml定义的内容
    private boolean dbFirst = true;         // 是否数据库定义优先 (shiro 在匹配时按照最先匹配原则)

    private PermissionService permissionService;

    @Override
    public Section getObject() throws Exception {
        Ini ini = new Ini();
        ini.load(getFilterChainDefinitions());

        /**
         * 参照{@link org.apache.shiro.spring.web.ShiroFilterFactoryBean#setFilterChainDefinitions(String)}
         * 虽然没有必要的, 但是如果明确指定 [urls] section,则只加载[urls] section
         */
        Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
        if (CollectionUtils.isEmpty(section)) {

            // 如果没有[urls]片段, 则定义包含在默认section中
            section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
        }

        // 将 数据库中加载的 权限信息存入 DB_SECTION_NAME section
        Section dbSection = ini.addSection(DB_SECTION_NAME);

        List<Permission> allPermissions = permissionService.findAll();
        for (Permission perm: allPermissions) {
            String url = perm.getUrl();
            /*
            Set<Action> actions = module.getActions();

            if (url == null || IGNORE_URL.equals(url) || mValue == null || actions == null) {
                continue;
            }

            if (url.endsWith("/")) {
                url.substring(0, url.length() - 1);
            }

            for (Action action : actions) {
                String aValue = action.getValue();
                dbSection.put(url + "/" + action, "perms[" + mValue + ":" + aValue + "]");
            }
            */
        }

        // 定义优先级处理
        if (dbFirst) {
            dbSection.putAll(section);
            section = dbSection;
        } else {
            section.putAll(dbSection);
        }

        return section;
    }

    @Override
    public Class<?> getObjectType() {
        return Section.class;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }

    public String getFilterChainDefinitions() {
        return filterChainDefinitions;
    }

    public void setFilterChainDefinitions(String filterChainDefinitions) {
        this.filterChainDefinitions = filterChainDefinitions;
    }

    public boolean isDbFirst() {
        return dbFirst;
    }

    public void setDbFirst(boolean dbFirst) {
        this.dbFirst = dbFirst;
    }
}
